package br.com.future.study.pool;

import java.util.ArrayList;
import java.util.Collection;

/**
 * Java Thread Pool This is a thread pool that for Java, it is simple to use and gets the job done. This program and all
 * supporting files are distributed under the Limited GNU Public License (LGPL, http://www.gnu.org). This is the main
 * class for the thread pool. You should create an instance of this class and assign tasks to it. For more information
 * visit http://www.jeffheaton.com.
 * 
 * @author Jeff Heaton (http://www.jeffheaton.com)
 * @version 1.0
 */
public class ThreadPool {

	/**
	 * The threads in the pool.
	 */
	protected Thread threadsArray[] = null;

	/**
	 * The backlog of assignments, which are waiting for the thread pool.
	 */
	Collection<Runnable> assignments = null;

	/**
	 * A Done object that is used to track when the thread pool is done, that is has no more work to perform.
	 */
	protected Done done = new Done();

	/**
	 * The constructor.
	 * 
	 * @param numberOfWorkers How many threads in the thread pool.
	 */
	public ThreadPool(int numberOfWorkers) {
		assignments = new ArrayList<Runnable>(numberOfWorkers);

		threadsArray = new WorkerThread[numberOfWorkers];
		for (int i = 0; i < threadsArray.length; i++) {
			threadsArray[i] = new WorkerThread(this);
			threadsArray[i].start();
		}
	}

	/**
	 * Add a task to the thread pool.
	 *
	 * Obs.Any class which implements the Runnable interface could be assigned. 
	 *
	 * When this task runs, its run method will be called.
	 *
	 * @param r An object that implements the Runnable interface
	 */
	public synchronized void addToPool(Runnable r) {
		done.workerBegin();
		assignments.add(r);
		notify();
	}

	/**
	 * Get a new work assignment.
	 *
	 * @return A new assignment
	 */
	public synchronized Runnable getAssignment() {
		try {
			while (!assignments.iterator().hasNext())
				wait();

			Runnable r = assignments.iterator().next();
			assignments.remove(r);
			return r;
		} catch (InterruptedException e) {
			done.workerEnd();
			return null;
		}
	}

	/**
	 * Called to block the current thread until the thread pool has no more work.
	 */
	public void complete() {
		done.waitBegin();
		done.waitDone();
	}

	protected void finalize() {
		done.reset();
		for (int i = 0; i < threadsArray.length; i++) {
			threadsArray[i].interrupt();
			done.workerBegin();
			//threadsArray[i].destroy();
		}
		done.waitDone();
	}
}

/**
 * The worker threads that make up the thread pool.
 * 
 * @author Jeff Heaton
 * @version 1.0
 */
class WorkerThread extends Thread {

	/**
	 * True if this thread is currently processing.
	 */
	public boolean busy;

	/**
	 * The thread pool that this object belongs to.
	 */
	public ThreadPool owner;

	/**
	 * The constructor.
	 * 
	 * @param o the thread pool
	 */
	WorkerThread(ThreadPool o) {
		owner = o;
	}

	/**
	 * Scan for and execute tasks.
	 */
	public void run() {
		Runnable target = null;

		do {
			target = owner.getAssignment();
			if (target != null) {
				target.run();
				owner.done.workerEnd();
			}
		} while (target != null);
	}
}
